package net.cyndeline.componentSystem.movement

import net.cyndeline.entitySystem.AbstractEventHandlerSystem
import net.cyndeline.entitySystem.defaultImpl.Aspect
import net.cyndeline.events.movement.MovementEvent
import net.cyndeline.components.world.PositionComponent
import net.cyndeline.components.world.OnMapComponent
import net.cyndeline.entitySystem.EntityRef
import net.cyndeline.entitySystem.Event
import net.cyndeline.GameMap.LevelMap
import net.cyndeline.components.world.OnMapComponent
import net.cyndeline.components.world.PositionComponent
import net.cyndeline.events.movement.MovementEvent
import net.cyndeline.components.world.OnMapComponent
import net.cyndeline.components.world.PositionComponent
import net.cyndeline.events.movement.MovementEvent

/**
 * Checks if an event is contains illegal data (such as attempting to
 * move an entity from a tile where it doesn't exist, or to a tile
 * outside the map). It handles them by throwing error exceptions,
 * causing the program to fail fast.
 */
class MovementErrorSystem() extends AbstractEventHandlerSystem(
      new Aspect().getAll(classOf[PositionComponent], classOf[OnMapComponent]),
      classOf[MovementEvent]) {
  
  override def onEvent(event: Event, entity: EntityRef) = event match {
    case move: MovementEvent => {
      process(move, entity)
    }
    case _ => {}
  }
  
  private def process(move: MovementEvent, entity: EntityRef) {
    
    /* Get() will throw an error on its own if the entity doesn't have
     * the required components.
     */
    val onMap = entity.getComponent(classOf[OnMapComponent]).get
    val position = entity.getComponent(classOf[PositionComponent]).get
    
    val map = onMap.map
    val startX = move.start._1
    val startY = move.start._2
    val stopX = move.stop._1
    val stopY = move.stop._2
    
    val entitiesAtStart = map.objectsAt(startX, startY)
    if (!(entitiesAtStart contains entity)) {
        throw new Error("Attempted to move " + entity + " from position " 
            + move.start + " on map " + map.name 
            + ", but the entity wasn't there.")
    }
    
    val entitiesAtStop = map.objectsAt(stopX, stopY)
    if (entitiesAtStop contains entity) {
        throw new Error("Attempted to move " + entity + " to position " 
            + move.stop + " on map " + map.name 
            + ", but the entity is already there.")
    }
  }
}